例子
需要先了解的内容
挂载
1 | ReactDOM.render(<App />, document.getElementById('container')) |
这段代码的含义是想在容器中渲染出一个组件。
fiber 对象
在 createFiberRoot
函数内部,分别创建了两个 root
,一个 root
叫做 FiberRoot
,另一个 root
叫做 RootFiber
,并且它们两者还是相互引用的。
对于 FiberRoot
对象来说,我们现在只需要了解两个属性,分别是 containerInfo
及 current
。前者代表着容器信息,也就是 document.querySelector('#container')
;后者指向 RootFiber
。
对于 RootFiber
对象来说,我们需要了解的属性稍微多点
1 | function FiberNode( |
return
、child
、sibling
这三个属性很重要,它们是构成 fiber
树的主体数据结构。fiber
树其实是一个单链表树结构,return
及 child
分别对应着树的父子节点,并且父节点只有一个 child
指向它的第一个子节点,即便是父节点有好多个子节点。那么多个子节点如何连接起来呢?答案是 sibling
,每个子节点都有一个 sibling
属性指向着下一个子节点,都有一个 return
属性指向着父节点。
从代码来看
1 | const APP = () => ( |
例子
通过一个例子看一下整个流程做了什么事情
1 | <html> |
首先 \<App /> 会生成 ReactELement
1 | function createElement(type, config, children) { |
生成的 ReactElement
之后进入 ReactDOM.render,第一个参数就是 ReactElement,第二个是 DOM 引用
进入 legacyRenderSubtreeIntoContainer 方法
1 | function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) { |
进入回调调用
1 | unbatchedUpdates(function() { |
进入 render
1 | ReactRoot.prototype.render = function (children, callback) { |
进入 updateContainer
1 | function updateContainer(element, container, parentComponent, callback) { |
进入 updateContainerAtExpirationTime
1 | function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) { |
进入 scheduleRootUpdate
1 | function scheduleRootUpdate(current$$1, element, expirationTime, callback) { |
进入在 renderRoot 方法里的 createWorkInProgress 方法后进入 createWorkInProgress 方法后,这里创建 FiberNode。而在 workLoop 方法创建完整的 Fiber 树的链接关系(主要是 beginWork 方法)。在 completeWork 方法里的 createInstance方法 生成 stateNode
1 | function createWorkInProgress(current, pendingProps, expirationTime) { |
补充
updatequeue
1 | function processUpdateQueue(workInProgress, queue, props, instance, renderExpirationTime) { |
看起来好像是合并多次操作的地方,到 setState 的地方再来看
小结
- createElement 生成 ReactComponent
- 进入 React.render 方法,创建 ReactRoot,它的 current 是 RootFiber,containerInfo 是模板插槽的引用
- 创建 updateQueue,单向链表,包含需要更新的
- 任务调度阶段
- 从 RootFiber 开始生成 Fiber 树,遇到组件会调用 render 方法生成新的 ReactComponent(从上到下)
- 当完成 Fiber 树结构之后,开始生成实例(stateNode)(从下到上,儿子实例被添加到父亲实例里)
- 提交阶段
- 把 DomElement 实例(就是stateNode)添加到模板插槽的位置
参考资料
语法:
1 | var event = document.createEvent(type) |
event
就是被创建的 Event 对象.type
是一个字符串,表示要创建的事件类型。事件类型可能包括"UIEvents"
,"MouseEvents"
,"MutationEvents"
, 或者"HTMLEvents"
。请查看 Notes 章节获取详细信息 。
用来初始化由Document.createEvent()
创建的 event
实例
语法:
1 | event.initEvent(type, bubbles, cancelable) |
type
一个DOMString
类型的字段,定义了事件的类型.bubbles
一个Boolean
值,决定是否事件是否应该向上冒泡. 一旦设置了这个值,只读属性Event.bubbles
也会获取相应的值.cancelable
一个Boolean
值,决定该事件的默认动作是否可以被取消. 一旦设置了这个值, 只读属性Event.cancelable
也会获取相应的值.
向一个指定的事件目标派发一个事件, 并以合适的顺序同步调用目标元素相关的事件处理函数。标准事件处理规则(包括事件捕获和可选的冒泡过程)同样适用于通过手动的使用dispatchEvent()
方法派发的事件。
语法:
1 | target.dispatchEvent(event) |
event
是要被派发的事件对象。target
被用来初始化 事件 和 决定将会触发 目标
整合上面 3 个的例子
1 |
|